﻿namespace Common
{
    using Microsoft.Extensions.Caching.Distributed;
    using Microsoft.Extensions.Caching.Memory;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Logging;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Diagnostics.Eventing.Reader;
    using System.Reflection;
    using System.Threading.Tasks;

    /// <summary>
    /// 缓存类
    /// </summary>
    //[Injection(typeof(ICacheService), InjectionType.Singleton)]
    public class CacheService : ICacheService
    {
        readonly IDistributedCache _cache;
        readonly IMemoryCache _memoryCache;
        readonly CacheType _cacheType;

        public CacheService(IServiceProvider serviceProvider, CacheType cacheType)
        {
            if(cacheType == CacheType.MemoryCache)
            {
                _memoryCache = serviceProvider.GetRequiredService<IMemoryCache>();
            }
            else
            {
                _cache = serviceProvider.GetRequiredService<IDistributedCache>();
            }
            _cacheType = cacheType;
        }

        protected string BuildKey(string idKey)
        {
            return $"Cache_{GetType().FullName}_{idKey}";
        }
        public void SetCache(string key, object value)
        {
            string cacheKey = BuildKey(key);
            if (_cacheType == CacheType.MemoryCache)
            {
                _memoryCache.Set(cacheKey, value);
            }
            else
            {
                _cache.SetString(cacheKey, value.ToJsonString());
            }
        }

        public async Task SetCacheAsync(string key, object value)
        {
            string cacheKey = BuildKey(key);
            if (_cacheType == CacheType.MemoryCache)
            {
                _memoryCache.Set(cacheKey, value);
                await Task.CompletedTask;
            }
            else
            {
                await _cache.SetStringAsync(cacheKey, value.ToJsonString());
            }
        }

        public void SetCache(string key, object value, TimeSpan timeout)
        {
            string cacheKey = BuildKey(key);
            if (_cacheType == CacheType.MemoryCache)
            {
                _memoryCache.Set(cacheKey, value, new MemoryCacheEntryOptions()
                {
                    //这里没转换标准时间，Linux时区会有问题？
                    AbsoluteExpiration = new DateTimeOffset(DateTime.Now + timeout)
                });
            }
            else
            {
                _cache.SetString(cacheKey, value.ToJsonString(), new DistributedCacheEntryOptions
                {
                    //这里没转换标准时间，Linux时区会有问题？
                    AbsoluteExpiration = new DateTimeOffset(DateTime.Now + timeout)
                });
            }
        }

        public async Task SetCacheAsync(string key, object value, TimeSpan timeout)
        {
            string cacheKey = BuildKey(key);
            if (_cacheType == CacheType.MemoryCache)
            {
                _memoryCache.Set(cacheKey, value, new MemoryCacheEntryOptions()
                {
                    //这里没转换标准时间，Linux时区会有问题？
                    AbsoluteExpiration = new DateTimeOffset(DateTime.Now + timeout)
                });
                await Task.CompletedTask;
            }
            else
            {
                await _cache.SetStringAsync(cacheKey, value.ToJsonString(), new DistributedCacheEntryOptions
                {
                    //这里没转换标准时间，Linux时区会有问题？
                    AbsoluteExpiration = new DateTimeOffset(DateTime.Now + timeout)
                });
            }
        }

        public void SetCache(string key, object value, TimeSpan timeout, ExpireType expireType)
        {
            string cacheKey = BuildKey(key);
            if (_cacheType == CacheType.MemoryCache)
            {
                if (expireType == ExpireType.Absolute)
                {
                    //这里没转换标准时间，Linux时区会有问题？
                    _memoryCache.Set(cacheKey, value.ToJsonString(), new MemoryCacheEntryOptions
                    {
                        AbsoluteExpiration = new DateTimeOffset(DateTime.Now + timeout)
                    });
                }
                else
                {
                    _memoryCache.Set(cacheKey, value.ToJsonString(), new MemoryCacheEntryOptions
                    {
                        AbsoluteExpirationRelativeToNow = timeout
                    });
                }
            }
            else
            {
                if (expireType == ExpireType.Absolute)
                {
                    //这里没转换标准时间，Linux时区会有问题？
                    _cache.SetString(cacheKey, value.ToJsonString(), new DistributedCacheEntryOptions
                    {
                        AbsoluteExpiration = new DateTimeOffset(DateTime.Now + timeout)
                    });
                }
                else
                {
                    _cache.SetString(cacheKey, value.ToJsonString(), new DistributedCacheEntryOptions
                    {
                        AbsoluteExpirationRelativeToNow = timeout
                    });
                }
            }
        }

        public async Task SetCacheAsync(string key, object value, TimeSpan timeout, ExpireType expireType)
        {
            string cacheKey = BuildKey(key);
            if (_cacheType == CacheType.MemoryCache)
            {
                if (expireType == ExpireType.Absolute)
                {
                    //这里没转换标准时间，Linux时区会有问题？
                    _memoryCache.Set(cacheKey, value.ToJsonString(), new MemoryCacheEntryOptions
                    {
                        AbsoluteExpiration = new DateTimeOffset(DateTime.Now + timeout)
                    });
                }
                else
                {
                    _memoryCache.Set(cacheKey, value.ToJsonString(), new MemoryCacheEntryOptions
                    {
                        AbsoluteExpirationRelativeToNow = timeout
                    });
                }
                await Task.CompletedTask;
            }
            else
            {
                if (expireType == ExpireType.Absolute)
                {
                    //这里没转换标准时间，Linux时区会有问题？
                    await _cache.SetStringAsync(cacheKey, value.ToJsonString(), new DistributedCacheEntryOptions
                    {
                        AbsoluteExpiration = new DateTimeOffset(DateTime.Now + timeout)
                    });
                }
                else
                {
                    await _cache.SetStringAsync(cacheKey, value.ToJsonString(), new DistributedCacheEntryOptions
                    {
                        AbsoluteExpirationRelativeToNow = timeout
                    });
                }
            }
        }

        public string GetCache(string idKey)
        {
            if (String.IsNullOrWhiteSpace(idKey))
            {
                return null;
            }
            string cacheKey = BuildKey(idKey);
            if (_cacheType == CacheType.MemoryCache)
            {
                return _memoryCache.Get<String>(cacheKey);
            }
            else
            {
                return _cache.GetString(cacheKey);
            }
        }
        public async Task<string> GetCacheAsync(string key)
        {
            if (String.IsNullOrWhiteSpace(key))
            {
                return null;
            }
            string cacheKey = BuildKey(key);
            if (_cacheType == CacheType.MemoryCache)
            {
                return await Task.FromResult(_memoryCache.Get<String>(cacheKey));
            }
            else
            {
                return await _cache.GetStringAsync(cacheKey);
            }
        }

        public T GetCache<T>(string key)
        {
            var cache = GetCache(key);

            if (!String.IsNullOrWhiteSpace(cache))
            {
                return cache.ToObject<T>();
            }
            return default(T);
        }

        public async Task<T> GetCacheAsync<T>(string key)
        {
            var cache = await GetCacheAsync(key);
            if (!string.IsNullOrEmpty(cache))
            {
                return cache.ToObject<T>();
            }
            return default(T);
        }

        public void RemoveCache(string key)
        {
            if (_cacheType == CacheType.MemoryCache)
            {
                _memoryCache.Remove(BuildKey(key));
            }
            else
            {
                _cache.Remove(BuildKey(key));
            }
        }

        public async Task RemoveCacheAsync(string key)
        {
            if (_cacheType == CacheType.MemoryCache)
            {
                _memoryCache.Remove(BuildKey(key));
                await Task.CompletedTask;
            }
            else
            {
                await _cache.RemoveAsync(BuildKey(key));
            }
        }

        public void RefreshCache(string key)
        {
            if (_cacheType == CacheType.MemoryCache)
            {
                //刷新缓存
            }
            else
            {
                _cache.Refresh(BuildKey(key));
            }
        }

        public async Task RefreshCacheAsync(string key)
        {
            if (_cacheType == CacheType.MemoryCache)
            {
                //刷新缓存
                await Task.CompletedTask;
            }
            else
            {
                await _cache.RefreshAsync(BuildKey(key));
            }
        }
    }
}

